/*>r6502main.c
 *
 * BBC 6502 to RISC OS library code
 * by Michael Foot.
 * Version 1.06 (26 May 2006).
 *
 */

/*#define __JMP_BUF_SIZE 100*/

/*#include <setjmp.h>*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "kernel.h"
#include "swis.h"

#include "r6502lib.h"

/*int a76489_lookup[0x400] =
{
0x0000,0xBEE7,0xAEE7,0xA58B,0x9EE7,0x99C1,0x958B,0x91FC,
0x8EE7,0x8C2F,0x89C1,0x878D,0x858B,0x83B2,0x81FC,0x8065,
0x7EE7,0x7D81,0x7C2F,0x7AF0,0x79C1,0x78A0,0x778D,0x7687,
0x758B,0x749A,0x73B2,0x72D3,0x71FC,0x712D,0x7065,0x6FA3,
0x6EE7,0x6E31,0x6D81,0x6CD6,0x6C2F,0x6B8D,0x6AF0,0x6A56,
0x69C1,0x692F,0x68A0,0x6815,0x678D,0x6709,0x6687,0x6608,
0x658B,0x6511,0x649A,0x6425,0x63B2,0x6342,0x62D3,0x6267,
0x61FC,0x6194,0x612D,0x60C8,0x6065,0x6003,0x5FA3,0x5F44,
0x5EE7,0x5E8C,0x5E31,0x5DD9,0x5D81,0x5D2B,0x5CD6,0x5C82,
0x5C2F,0x5BDE,0x5B8D,0x5B3E,0x5AF0,0x5AA2,0x5A56,0x5A0B,
0x59C1,0x5977,0x592F,0x58E7,0x58A0,0x585A,0x5815,0x57D1,
0x578D,0x574B,0x5709,0x56C7,0x5687,0x5647,0x5608,0x55C9,
0x558B,0x554E,0x5511,0x54D5,0x549A,0x545F,0x5425,0x53EB,
0x53B2,0x537A,0x5342,0x530A,0x52D3,0x529D,0x5267,0x5231,
0x51FC,0x51C8,0x5194,0x5160,0x512D,0x50FA,0x50C8,0x5096,
0x5065,0x5034,0x5003,0x4FD3,0x4FA3,0x4F73,0x4F44,0x4F16,
0x4EE7,0x4EB9,0x4E8C,0x4E5E,0x4E31,0x4E05,0x4DD9,0x4DAD,
0x4D81,0x4D56,0x4D2B,0x4D00,0x4CD6,0x4CAC,0x4C82,0x4C58,
0x4C2F,0x4C06,0x4BDE,0x4BB5,0x4B8D,0x4B65,0x4B3E,0x4B17,
0x4AF0,0x4AC9,0x4AA2,0x4A7C,0x4A56,0x4A30,0x4A0B,0x49E6,
0x49C1,0x499C,0x4977,0x4953,0x492F,0x490B,0x48E7,0x48C4,
0x48A0,0x487D,0x485A,0x4838,0x4815,0x47F3,0x47D1,0x47AF,
0x478D,0x476C,0x474B,0x4729,0x4709,0x46E8,0x46C7,0x46A7,
0x4687,0x4667,0x4647,0x4627,0x4608,0x45E8,0x45C9,0x45AA,
0x458B,0x456D,0x454E,0x4530,0x4511,0x44F3,0x44D5,0x44B8,
0x449A,0x447C,0x445F,0x4442,0x4425,0x4408,0x43EB,0x43CF,
0x43B2,0x4396,0x437A,0x435E,0x4342,0x4326,0x430A,0x42EF,
0x42D3,0x42B8,0x429D,0x4282,0x4267,0x424C,0x4231,0x4217,
0x41FC,0x41E2,0x41C8,0x41AE,0x4194,0x417A,0x4160,0x4146,
0x412D,0x4113,0x40FA,0x40E1,0x40C8,0x40AF,0x4096,0x407D,
0x4065,0x404C,0x4034,0x401B,0x4003,0x3FEB,0x3FD3,0x3FBB,
0x3FA3,0x3F8B,0x3F73,0x3F5C,0x3F44,0x3F2D,0x3F16,0x3EFE,
0x3EE7,0x3ED0,0x3EB9,0x3EA2,0x3E8C,0x3E75,0x3E5E,0x3E48,
0x3E31,0x3E1B,0x3E05,0x3DEF,0x3DD9,0x3DC2,0x3DAD,0x3D97,
0x3D81,0x3D6B,0x3D56,0x3D40,0x3D2B,0x3D15,0x3D00,0x3CEB,
0x3CD6,0x3CC1,0x3CAC,0x3C97,0x3C82,0x3C6D,0x3C58,0x3C44,
0x3C2F,0x3C1B,0x3C06,0x3BF2,0x3BDE,0x3BC9,0x3BB5,0x3BA1,
0x3B8D,0x3B79,0x3B65,0x3B52,0x3B3E,0x3B2A,0x3B17,0x3B03,
0x3AF0,0x3ADC,0x3AC9,0x3AB6,0x3AA2,0x3A8F,0x3A7C,0x3A69,
0x3A56,0x3A43,0x3A30,0x3A1E,0x3A0B,0x39F8,0x39E6,0x39D3,
0x39C1,0x39AE,0x399C,0x3989,0x3977,0x3965,0x3953,0x3941,
0x392F,0x391D,0x390B,0x38F9,0x38E7,0x38D5,0x38C4,0x38B2,
0x38A0,0x388F,0x387D,0x386C,0x385A,0x3849,0x3838,0x3826,
0x3815,0x3804,0x37F3,0x37E2,0x37D1,0x37C0,0x37AF,0x379E,
0x378D,0x377D,0x376C,0x375B,0x374B,0x373A,0x3729,0x3719,
0x3709,0x36F8,0x36E8,0x36D8,0x36C7,0x36B7,0x36A7,0x3697,
0x3687,0x3677,0x3667,0x3657,0x3647,0x3637,0x3627,0x3617,
0x3608,0x35F8,0x35E8,0x35D9,0x35C9,0x35BA,0x35AA,0x359B,
0x358B,0x357C,0x356D,0x355D,0x354E,0x353F,0x3530,0x3520,
0x3511,0x3502,0x34F3,0x34E4,0x34D5,0x34C6,0x34B8,0x34A9,
0x349A,0x348B,0x347C,0x346E,0x345F,0x3451,0x3442,0x3433,
0x3425,0x3416,0x3408,0x33FA,0x33EB,0x33DD,0x33CF,0x33C0,
0x33B2,0x33A4,0x3396,0x3388,0x337A,0x336C,0x335E,0x3350,
0x3342,0x3334,0x3326,0x3318,0x330A,0x32FC,0x32EF,0x32E1,
0x32D3,0x32C6,0x32B8,0x32AA,0x329D,0x328F,0x3282,0x3274,
0x3267,0x3259,0x324C,0x323F,0x3231,0x3224,0x3217,0x3209,
0x31FC,0x31EF,0x31E2,0x31D5,0x31C8,0x31BB,0x31AE,0x31A1,
0x3194,0x3187,0x317A,0x316D,0x3160,0x3153,0x3146,0x313A,
0x312D,0x3120,0x3113,0x3107,0x30FA,0x30EE,0x30E1,0x30D4,
0x30C8,0x30BB,0x30AF,0x30A2,0x3096,0x308A,0x307D,0x3071,
0x3065,0x3058,0x304C,0x3040,0x3034,0x3027,0x301B,0x300F,
0x3003,0x2FF7,0x2FEB,0x2FDF,0x2FD3,0x2FC7,0x2FBB,0x2FAF,
0x2FA3,0x2F97,0x2F8B,0x2F7F,0x2F73,0x2F68,0x2F5C,0x2F50,
0x2F44,0x2F39,0x2F2D,0x2F21,0x2F16,0x2F0A,0x2EFE,0x2EF3,
0x2EE7,0x2EDC,0x2ED0,0x2EC5,0x2EB9,0x2EAE,0x2EA2,0x2E97,
0x2E8C,0x2E80,0x2E75,0x2E6A,0x2E5E,0x2E53,0x2E48,0x2E3D,
0x2E31,0x2E26,0x2E1B,0x2E10,0x2E05,0x2DFA,0x2DEF,0x2DE4,
0x2DD9,0x2DCD,0x2DC2,0x2DB8,0x2DAD,0x2DA2,0x2D97,0x2D8C,
0x2D81,0x2D76,0x2D6B,0x2D60,0x2D56,0x2D4B,0x2D40,0x2D35,
0x2D2B,0x2D20,0x2D15,0x2D0B,0x2D00,0x2CF5,0x2CEB,0x2CE0,
0x2CD6,0x2CCB,0x2CC1,0x2CB6,0x2CAC,0x2CA1,0x2C97,0x2C8C,
0x2C82,0x2C77,0x2C6D,0x2C63,0x2C58,0x2C4E,0x2C44,0x2C39,
0x2C2F,0x2C25,0x2C1B,0x2C10,0x2C06,0x2BFC,0x2BF2,0x2BE8,
0x2BDE,0x2BD4,0x2BC9,0x2BBF,0x2BB5,0x2BAB,0x2BA1,0x2B97,
0x2B8D,0x2B83,0x2B79,0x2B6F,0x2B65,0x2B5C,0x2B52,0x2B48,
0x2B3E,0x2B34,0x2B2A,0x2B20,0x2B17,0x2B0D,0x2B03,0x2AF9,
0x2AF0,0x2AE6,0x2ADC,0x2AD3,0x2AC9,0x2ABF,0x2AB6,0x2AAC,
0x2AA2,0x2A99,0x2A8F,0x2A86,0x2A7C,0x2A73,0x2A69,0x2A60,
0x2A56,0x2A4D,0x2A43,0x2A3A,0x2A30,0x2A27,0x2A1E,0x2A14,
0x2A0B,0x2A02,0x29F8,0x29EF,0x29E6,0x29DC,0x29D3,0x29CA,
0x29C1,0x29B7,0x29AE,0x29A5,0x299C,0x2993,0x2989,0x2980,
0x2977,0x296E,0x2965,0x295C,0x2953,0x294A,0x2941,0x2938,
0x292F,0x2926,0x291D,0x2914,0x290B,0x2902,0x28F9,0x28F0,
0x28E7,0x28DE,0x28D5,0x28CC,0x28C4,0x28BB,0x28B2,0x28A9,
0x28A0,0x2897,0x288F,0x2886,0x287D,0x2874,0x286C,0x2863,
0x285A,0x2852,0x2849,0x2840,0x2838,0x282F,0x2826,0x281E,
0x2815,0x280D,0x2804,0x27FC,0x27F3,0x27EA,0x27E2,0x27D9,
0x27D1,0x27C8,0x27C0,0x27B7,0x27AF,0x27A7,0x279E,0x2796,
0x278D,0x2785,0x277D,0x2774,0x276C,0x2764,0x275B,0x2753,
0x274B,0x2742,0x273A,0x2732,0x2729,0x2721,0x2719,0x2711,
0x2709,0x2700,0x26F8,0x26F0,0x26E8,0x26E0,0x26D8,0x26CF,
0x26C7,0x26BF,0x26B7,0x26AF,0x26A7,0x269F,0x2697,0x268F,
0x2687,0x267F,0x2677,0x266F,0x2667,0x265F,0x2657,0x264F,
0x2647,0x263F,0x2637,0x262F,0x2627,0x261F,0x2617,0x260F,
0x2608,0x2600,0x25F8,0x25F0,0x25E8,0x25E0,0x25D9,0x25D1,
0x25C9,0x25C1,0x25BA,0x25B2,0x25AA,0x25A2,0x259B,0x2593,
0x258B,0x2584,0x257C,0x2574,0x256D,0x2565,0x255D,0x2556,
0x254E,0x2546,0x253F,0x2537,0x2530,0x2528,0x2520,0x2519,
0x2511,0x250A,0x2502,0x24FB,0x24F3,0x24EC,0x24E4,0x24DD,
0x24D5,0x24CE,0x24C6,0x24BF,0x24B8,0x24B0,0x24A9,0x24A1,
0x249A,0x2493,0x248B,0x2484,0x247C,0x2475,0x246E,0x2466,
0x245F,0x2458,0x2451,0x2449,0x2442,0x243B,0x2433,0x242C,
0x2425,0x241E,0x2416,0x240F,0x2408,0x2401,0x23FA,0x23F2,
0x23EB,0x23E4,0x23DD,0x23D6,0x23CF,0x23C8,0x23C0,0x23B9,
0x23B2,0x23AB,0x23A4,0x239D,0x2396,0x238F,0x2388,0x2381,
0x237A,0x2373,0x236C,0x2365,0x235E,0x2357,0x2350,0x2349,
0x2342,0x233B,0x2334,0x232D,0x2326,0x231F,0x2318,0x2311,
0x230A,0x2303,0x22FC,0x22F5,0x22EF,0x22E8,0x22E1,0x22DA,
0x22D3,0x22CC,0x22C6,0x22BF,0x22B8,0x22B1,0x22AA,0x22A4,
0x229D,0x2296,0x228F,0x2288,0x2282,0x227B,0x2274,0x226D,
0x2267,0x2260,0x2259,0x2253,0x224C,0x2245,0x223F,0x2238,
0x2231,0x222B,0x2224,0x221D,0x2217,0x2210,0x2209,0x2203,
0x21FC,0x21F6,0x21EF,0x21E9,0x21E2,0x21DB,0x21D5,0x21CE,
0x21C8,0x21C1,0x21BB,0x21B4,0x21AE,0x21A7,0x21A1,0x219A,
0x2194,0x218D,0x2187,0x2180,0x217A,0x2173,0x216D,0x2167,
0x2160,0x215A,0x2153,0x214D,0x2146,0x2140,0x213A,0x2133,
0x212D,0x2127,0x2120,0x211A,0x2113,0x210D,0x2107,0x2101,
0x20FA,0x20F4,0x20EE,0x20E7,0x20E1,0x20DB,0x20D4,0x20CE,
0x20C8,0x20C2,0x20BB,0x20B5,0x20AF,0x20A9,0x20A2,0x209C,
0x2096,0x2090,0x208A,0x2083,0x207D,0x2077,0x2071,0x206B,
0x2065,0x205E,0x2058,0x2052,0x204C,0x2046,0x2040,0x203A,
0x2034,0x202D,0x2027,0x2021,0x201B,0x2015,0x200F,0x2009,
0x2003,0x1FFD,0x1FF7,0x1FF1,0x1FEB,0x1FE5,0x1FDF,0x1FD9,
0x1FD3,0x1FCD,0x1FC7,0x1FC1,0x1FBB,0x1FB5,0x1FAF,0x1FA9,
0x1FA3,0x1F9D,0x1F97,0x1F91,0x1F8B,0x1F85,0x1F7F,0x1F79,
0x1F73,0x1F6D,0x1F68,0x1F62,0x1F5C,0x1F56,0x1F50,0x1F4A,
0x1F44,0x1F3E,0x1F39,0x1F33,0x1F2D,0x1F27,0x1F21,0x1F1B,
0x1F16,0x1F10,0x1F0A,0x1F04,0x1EFE,0x1EF9,0x1EF3,0x1EED
};*/

int a76489_lookup[4][0x100] =
{{
  /*0*/
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
},{
  /*1*/
  0x0000,0x1F97,0x1FEB,0x2040,0x209C,0x20EE,0x2140,0x2194,
  0x21EF,0x223F,0x228F,0x22E1,0x2349,0x239D,0x23F2,0x2449,
  0x249A,0x24EC,0x253F,0x2593,0x25F0,0x263F,0x268F,0x26E0,
  0x274B,0x279E,0x27F3,0x2849,0x28A0,0x28F0,0x2941,0x2993,
  0x29EF,0x2A43,0x2A99,0x2AF0,0x2B48,0x2B97,0x2BE8,0x2C39,
  0x2CA1,0x2CF5,0x2D4B,0x2DA2,0x2DEF,0x2E3D,0x2E8C,0x2EDC,
  0x2F44,0x2F97,0x2FEB,0x3040,0x30A2,0x30EE,0x3146,0x3194,
  0x31EF,0x323F,0x328F,0x32E1,0x3350,0x33A4,0x33FA,0x3451,
  0x349A,0x34F3,0x353F,0x359B,0x35F8,0x3647,0x3697,0x36E8,
  0x374B,0x379E,0x37F3,0x3849,0x38A0,0x38F9,0x3941,0x399C,
  0x39F8,0x3A43,0x3AA2,0x3AF0,0x3B52,0x3BA1,0x3BF2,0x3C44,
  0x3CAC,0x3D00,0x3D56,0x3DAD,0x3DEF,0x3E48,0x3E8C,0x3EE7,
  0x3F44,0x3FA3,0x3FEB,0x404C,0x40AF,0x40FA,0x4146,0x4194,
  0x41FC,0x424C,0x429D,0x42EF,0x435E,0x43B2,0x4408,0x445F,
  0x449A,0x44F3,0x454E,0x45AA,0x4608,0x4647,0x46A7,0x46E8,
  0x474B,0x47AF,0x47F3,0x485A,0x48A0,0x490B,0x4953,0x499C,
  0x4A0B,0x4A56,0x4AA2,0x4AF0,0x4B65,0x4BB5,0x4C06,0x4C58,
  0x4CAC,0x4D00,0x4D56,0x4DAD,0x4E05,0x4E5E,0x4E8C,0x4EE7,
  0x4F44,0x4FA3,0x5003,0x5065,0x50C8,0x50FA,0x5160,0x5194,
  0x51FC,0x5267,0x529D,0x530A,0x537A,0x53B2,0x5425,0x545F,
  0x549A,0x5511,0x554E,0x55C9,0x5608,0x5647,0x56C7,0x5709,
  0x574B,0x57D1,0x5815,0x585A,0x58A0,0x592F,0x5977,0x59C1,
  0x5A0B,0x5A56,0x5AA2,0x5AF0,0x5B8D,0x5BDE,0x5C2F,0x5C82,
  0x5CD6,0x5D2B,0x5D81,0x5DD9,0x5E31,0x5E8C,0x5E8C,0x5EE7,
  0x5F44,0x5FA3,0x6003,0x6065,0x60C8,0x612D,0x6194,0x6194,
  0x61FC,0x6267,0x62D3,0x6342,0x63B2,0x63B2,0x6425,0x649A,
  0x649A,0x6511,0x658B,0x6608,0x6608,0x6687,0x6709,0x6709,
  0x678D,0x6815,0x6815,0x68A0,0x68A0,0x692F,0x69C1,0x69C1,
  0x6A56,0x6A56,0x6AF0,0x6AF0,0x6B8D,0x6C2F,0x6C2F,0x6CD6,
  0x6CD6,0x6D81,0x6D81,0x6E31,0x6E31,0x6EE7,0x6EE7,0x6EE7,
  0x6FA3,0x6FA3,0x7065,0x7065,0x712D,0x712D,0x71FC,0x71FC,
  0x71FC,0x72D3,0x72D3,0x73B2,0x73B2,0x73B2,0x749A,0x749A
},{
  /*2*/
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x2396,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x28E7,0x0000,0x0000,
  0x0000,0x2A3A,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x2CEB,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x2F8B,0x0000,0x0000,0x0000,0x30E1,0x0000,0x0000,
  0x0000,0x3231,0x0000,0x0000,0x0000,0x3396,0x0000,0x0000,
  0x0000,0x34E4,0x0000,0x0000,0x0000,0x3637,0x0000,0x0000,
  0x0000,0x378D,0x0000,0x0000,0x0000,0x38E7,0x0000,0x0000,
  0x0000,0x3A30,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x3CEB,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x3F8B,0x0000,0x0000,0x0000,0x40E1,0x0000,0x0000,
  0x0000,0x4231,0x0000,0x0000,0x0000,0x4396,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x4627,0x0000,0x0000,
  0x0000,0x478D,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x4A30,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x4CD6,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x50C8,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x537A,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x6194,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
},{
  /*3*/
  0x1F39,0x1F8B,0x1FDF,0x2034,0x2090,0x20E1,0x2133,0x2187,
  0x21E2,0x2231,0x2282,0x22D3,0x233B,0x238F,0x23E4,0x243B,
  0x248B,0x24DD,0x2530,0x2584,0x25E0,0x262F,0x267F,0x26CF,
  0x273A,0x278D,0x27E2,0x2838,0x288F,0x28DE,0x292F,0x2980,
  0x29DC,0x2A30,0x2A86,0x2ADC,0x2B34,0x2B83,0x2BD4,0x2C25,
  0x2C8C,0x2CE0,0x2D35,0x2D8C,0x2DD9,0x2E26,0x2E75,0x2EC5,
  0x2F2D,0x2F7F,0x2FD3,0x3027,0x308A,0x30D4,0x312D,0x317A,
  0x31D5,0x3224,0x3274,0x32C6,0x3334,0x3388,0x33DD,0x3433,
  0x347C,0x34D5,0x3520,0x357C,0x35D9,0x3627,0x3677,0x36C7,
  0x3729,0x377D,0x37D1,0x3826,0x387D,0x38D5,0x391D,0x3977,
  0x39D3,0x3A1E,0x3A7C,0x3AC9,0x3B2A,0x3B79,0x3BC9,0x3C1B,
  0x3C82,0x3CD6,0x3D2B,0x3D81,0x3DC2,0x3E1B,0x3E5E,0x3EB9,
  0x3F16,0x3F73,0x3FBB,0x401B,0x407D,0x40C8,0x4113,0x4160,
  0x41C8,0x4217,0x4267,0x42B8,0x4326,0x437A,0x43CF,0x4425,
  0x445F,0x44B8,0x4511,0x456D,0x45C9,0x4608,0x4667,0x46A7,
  0x4709,0x476C,0x47AF,0x4815,0x485A,0x48C4,0x490B,0x4953,
  0x49C1,0x4A0B,0x4A56,0x4AA2,0x4B17,0x4B65,0x4BB5,0x4C06,
  0x4C58,0x4CAC,0x4D00,0x4D56,0x4DAD,0x4E05,0x4E31,0x4E8C,
  0x4EE7,0x4F44,0x4FA3,0x5003,0x5065,0x5096,0x50FA,0x512D,
  0x5194,0x51FC,0x5231,0x529D,0x530A,0x5342,0x53B2,0x53EB,
  0x5425,0x549A,0x54D5,0x554E,0x558B,0x55C9,0x5647,0x5687,
  0x56C7,0x574B,0x578D,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
}};

int video_base_addr[8] =
{0x3000,0x3000,0x3000,0x5800,0x5800,0x5800,0x5800,0x7C00};
/*colour lookup table for modes 0, 3, 4 and 6*/
int video_colourlookup1[0x10] = {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1};
/*colour lookup table for modes 1 and 5*/
int video_colourlookup2[0x10] = {0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3};
char videoula_physical0[0x10] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};
char videoula_physical1[0x10] = {0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0};
char videoula_palette0[0x10] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};
char videoula_palette1[0x10] = {0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0};
char videoula_palette[0x10];

char (*moderead)(int address);
void (*modewrite)(int address, char value);

_kernel_swi_regs regs;
/*jmp_buf jmpbuffer;*/
clock_t timer, video_timer;

char memory[0x10000];
char r6502_a;
char r6502_x;
char r6502_y;
char r6502_sp;
char r6502_ps;

int address;
char value1, value2;
char nlo, nhi;

char buffer1[12];
char buffer2[12];

/*int channeltime[4];*/

int loc_video_addr; /*screen address of local system*/
int bbc_video_mode; /*bbc video_mode*/
int bbc_video_addr; /*bbc video address*/
int videoula_palettevalue;
int videoula_flashcolour;

/* Default to trying to get a double height 256 colour mode */
int screen_256colour = 1;
int double_height = 1;

/* VDU intercepts */
char vdu_buffer[10];
int vdu_current = 0;
int vdu_count = 0;
/* Routine to display text */
void (*vdu_text)(char ch);

/* passthrough routined */
void vdupass(void);

/* Ignore sequence */
void vduignore(void)
{
}


/* Intercepts for control codes */
struct
{
	int num_chars;
	void (*execute)(void);
} vdu_intercept[32];

/* Outline font handling */
int outline_font = 0;
int font_handle = 0;
int base_line = 0;

/* Default palette for mode 2 */
int mode_palette[16] = 
  {
  0x00000000, /* black */
  0x0000FF00, /* red */
  0x00FF0000, /* green */
  0x00FFFF00, /* yellow */
  0xFF000000, /* blue */
  0xFF00FF00, /* magenta */
  0xFFFF0000, /* cyan */
  0xFFFFFF00, /* white */
  /* No flashing so just repeat the above */
  0x00000000, /* black */
  0x0000FF00, /* red */
  0x00FF0000, /* green */
  0x00FFFF00, /* yellow */
  0xFF000000, /* blue */
  0xFF00FF00, /* magenta */
  0xFFFF0000, /* cyan */
  0xFFFFFF00 /* white */
  };

int font_palette[16];

int last_font_foreground = -1;
int last_font_background = -1;
int graphics_plot = 0;
int graphics_foreground = 7;
int graphics_background = 0;
int text_foreground = 7;
int text_background = 0;

int quit, escape;

/**
 * Scale text up in vdu 4 mode
 */
void vdu4text(char ch)
{
	int text_x, text_y;
	int x, y;

   _swix(OS_SetColour,_INR(0,1), 0, text_background);

   _swix(OS_Byte, _IN(0)|_OUTR(1,2), 134, &text_x, &text_y);
   x = (text_x << 6);
   y = 1023 - (text_y << 5);

   bbcvdu(9); /* Ensure text cursor position is updated */
   _swix(OS_Plot, _INR(0,2), 4, x, y);
   _swix(OS_Plot, _INR(0,2), 97, 62, -30);

   _swix(OS_SetColour,_INR(0,1), 0, text_foreground);

   _swix(OS_Plot, _INR(0,2),4, x, y);
   bbcvdu(5);bbcvdu(ch);bbcvdu(4);

   _swix(OS_SetColour,_INR(0,1), graphics_plot, graphics_foreground);
}

/**
 * Display text in outline font.
 */
void font_text_vdu5(char ch)
{
   int x, y;
   int vars[3], vals[2];
   vars[0] = 138; /* Graphics cursor x */
   vars[1] = 139; /* Graphics cursor y */
   vars[2] = -1;

   _swix(OS_ReadVduVariables, _INR(0,1), vars, vals);

   /* Wide characters used for Mode 2 mess with the os units
      for the font so we need to multiply x by 4*/
   x = vals[0]<<2;
   y = vals[1] - base_line;

   if (last_font_foreground != graphics_foreground || last_font_background != graphics_background)
   {
	   last_font_foreground = graphics_foreground;
	   last_font_background = graphics_background;

       _swix(ColourTrans_SetFontColours, _INR(0,3), font_handle,
		   font_palette[last_font_background & 15],
		   font_palette[last_font_foreground & 15],
		   14);
   }

   _swix(Font_Paint, _INR(0,4)|_IN(7),
       font_handle, &ch,
       (1<<4)|(1<<7)|(1<<8),
        x,y,1);

   /* Move graphics cursor */
   _swix(OS_Plot, _INR(0,2), 0, 64, 0);
}

/**
 * Display outline font text when in vdu 4 mode
 */
void font_text(char ch)
{
   int text_x, text_y;
   int x, y;
   int rubout_box[8];
   
   if (ch > 128)
   {
	   /* Catch redefined characters */
	   vdu4text(ch);
	   return;
   }

   _swix(OS_Byte, _IN(0)|_OUTR(1,2), 134, &text_x, &text_y);
   x = (text_x << 6);
   y = 1023 - (text_y << 5);
   /* Wide characters used for Mode 2 mess with the os units
      for the font so we need to multiply x by 4*/
   x <<= 2;

   bbcvdu(9); /* Ensure text cursor position is updated */

   if (last_font_foreground != text_foreground || last_font_background != text_background)
   {
	   last_font_foreground = text_foreground;
	   last_font_background = text_background;

       _swix(ColourTrans_SetFontColours, _INR(0,3), font_handle,
		   font_palette[last_font_background & 15],
		   font_palette[last_font_foreground & 15],
		   14);
   }

   /* Set rubout box */
   _swix(OS_Plot, _INR(0,2), 4, x, y-32);
   _swix(OS_Plot, _INR(0,2), 4, x+64, y);

   _swix(Font_Paint, _INR(0,4)|_IN(7),
       font_handle, &ch,
       (1<<1)|(1<<4)|(1<<7)|(1<<8),
        x,y - base_line,1);
}

void vdu19font(void)
{
	vdupass(); // Set normal palette settings

	if (vdu_buffer[2] < 16)
	{
		font_palette[vdu_buffer[1]] = mode_palette[vdu_buffer[2]];
	} else if (vdu_buffer[2] == 16 || vdu_buffer[2] == 17)
	{
		font_palette[vdu_buffer[1]] = (((int)vdu_buffer[3]) << 8)
			+ (((int)vdu_buffer[4]) << 16) 
			+ (((int)vdu_buffer[5]) << 24);
	}

	// Don't support second flash colour (18) or borders etc
}

/**
 * Change VDU 17 change text colour to OS_SetColour
 */
void vdu17setcolour()
{
	regs.r[0] = (1<<6);
	if (vdu_buffer[1] & 128)
	{
		vdu_buffer[1] &= ~128;
		text_background = vdu_buffer[1];
		regs.r[0] |= (1<<4);
	} else
		text_foreground = vdu_buffer[1];

	regs.r[1] = vdu_buffer[1];
	_kernel_swi(OS_SetColour, &regs, &regs);
}

/**
 * Change VDU 18 change graphic colour to OS_SetColour
 *
 * Stores colours for use with font painting
 */
void vdu18setcolour()
{
	regs.r[0] = graphics_plot = (vdu_buffer[1] & 15);
	if (vdu_buffer[2] & 128) 
	{
		vdu_buffer[2] &= ~128;
		graphics_background = vdu_buffer[2];
		regs.r[0] |= (1<<4);
	} else
		graphics_foreground = vdu_buffer[2];

	regs.r[1] = vdu_buffer[2];
	_kernel_swi(OS_SetColour, &regs, &regs);	
}

/**
 * Intercept reset VDU as it also sets palette to the
 * default for the mode and this is not what is required
 * for the default 256 colour modes.
 */
void vdu20reset(void)
{
  bbcvdu(20); /* Reset everything */

  text_foreground = graphics_foreground = 7;
  text_background = graphics_background = 0;
  graphics_plot = 0;

  if (screen_256colour)
  {
  	  char osword12[5]; /* palette setting block */
	  int pal;

	  /* Set to default palette */
	  osword12[2] = osword12[3] = osword12[4] = 0;
	  for (pal = 0; pal < 16; pal++)
	  {
		  osword12[0] = pal;
		  osword12[1] = pal;
		  _swix(OS_Word, _INR(0,1), 12, osword12);
	  }
  }
}

int getword(char *block)
{
  int nreturn;
  nreturn = block[0];
  nreturn |= (block[1] << 8);
  nreturn |= (block[2] << 16);
  nreturn |= (block[3] << 24);
  return (nreturn);
}

void setword(char *block,int value)
{
  block[0] = (value & 0xFF);
  block[1] = (value & 0xFF00) >> 8;
  block[2] = (value & 0xFF0000) >> 16;
  block[3] = (value & 0xFF000000) >> 24;
}

void sound(void)
{
  int address,channel,amplitude,pitch,duration;
  address = (r6502_y << 8) | r6502_x;
  channel = (memory[address] & 0x0F);
  amplitude = (memory[address+3] << 8) | memory[address+2];
  if (amplitude > 0)
    amplitude = -15;
  else if (amplitude != 0)
    amplitude |= 0xFFFF0000; /*-= 0x10000;*/
  pitch = (memory[address+5] << 8) | memory[address+4];
  duration = (memory[address+7] << 8) | memory[address+6];
  if (channel == 0)
  {
    /*printf("SOUND A&%X:C&%X A&%X P&%X D&%X L&%X\n",address,channel, amplitude,
pitch, duration, a76489_lookup[channel][pitch]);*/
    if (amplitude == 0)
    {
      regs.r[0] = 1;
      regs.r[1] = 0;
      regs.r[2] = 0;
      regs.r[3] = 1;
      _kernel_swi(Sound_Control,&regs,&regs);
    }
    else
    {
      regs.r[0] = 1;
      regs.r[1] = amplitude;
      regs.r[2] = 0x8000+pitch;
      regs.r[3] = duration;
      _kernel_swi(Sound_Control,&regs,&regs);
    }
  }
  else
  {
    /*printf("SOUND A&%X:C&%X A&%X P&%X D&%X L&%X\n",address,channel, amplitude,
pitch, duration, a76489_lookup[channel][pitch]);*/
    if (amplitude == 0)
    {
      regs.r[0] = (channel+1);
      regs.r[1] = 0;
      regs.r[2] = a76489_lookup[channel][pitch];
      regs.r[3] = 1;
      _kernel_swi(Sound_Control,&regs,&regs);
    }
    else
    {
      regs.r[0] = (channel+1);
      regs.r[1] = amplitude;
      regs.r[2] = a76489_lookup[channel][pitch];
      regs.r[3] = duration;
      _kernel_swi(Sound_Control,&regs,&regs);
    }
  }
  /*if (duration == 0xFF)
    channeltime[channel] = 0;
  else
  {
    if (channeltime[channel] > 0)
    {
      while (clock() < channeltime[channel])
      {
      }
    }
    channeltime[channel] = clock() + (duration << 1);
  }*/
}

void osword(void)
{
  int address;
  switch (r6502_a)
  {
    case 0x00:
      /*read line from currently selected input into memory*/
      address = ((r6502_y << 8) | r6502_x);
      regs.r[0] = (int)(memory+((memory[address+1] << 8) | memory[address]));
      regs.r[1] = memory[address+2];
      regs.r[2] = memory[address+3];
      regs.r[3] = memory[address+4];
      _kernel_swi(OS_ReadLine,&regs,&regs);
      r6502_y = (regs.r[1] & 0xFF)+1;
      break;
    case 0x03:
      /*read interval timer*/
      regs.r[0] = 0x03;
      regs.r[1] = (int)(memory+((r6502_y << 8) | r6502_x));
      _kernel_swi(OS_Word,&regs,&regs);
      break;
    case 0x04:
      /*write interval timer*/
      regs.r[0] = 0x04;
      regs.r[1] = (int)(memory+((r6502_y << 8) | r6502_x));
      _kernel_swi(OS_Word,&regs,&regs);
      break;
    case 0x07:
      /*SOUND command*/
      sound();
      break;
    case 0x0A:
      /*read a character definition*/
      address = ((r6502_y << 8) | r6502_x);
      regs.r[0] = 0x0A;
      regs.r[1] = (int)(memory+address);
      _kernel_swi(OS_Word,&regs,&regs);
      break;
    default:
      regs.r[0] = r6502_a;
      regs.r[1] = r6502_x;
      regs.r[2] = r6502_y;
      _kernel_swi(OS_Word,&regs,&regs);
      r6502_x = (regs.r[1] & 0xFF);
      r6502_y = (regs.r[2] & 0xFF);
      break;
  }
}

/* Intercept oswrch */
void oswrch(void)
{
  if (vdu_count)
  {
    vdu_buffer[vdu_count++] = r6502_a;
    if (vdu_count == vdu_intercept[vdu_current].num_chars)
    {
      (*vdu_intercept[vdu_current].execute)();
      vdu_count = 0;
    }
  } else if  (r6502_a < 32)
  {
    if (vdu_intercept[r6502_a].num_chars)
    {
      vdu_current = r6502_a;
      vdu_buffer[vdu_count++] = r6502_a;
      if (vdu_count == vdu_intercept[vdu_current].num_chars)
      {
         (*vdu_intercept[vdu_current].execute)();
         vdu_count = 0;
      }
    } else
      bbcvdu(r6502_a);
  } else
    vdu_text(r6502_a);
}

void r6502adc(int n)
{
  int nval;
  int nlob, nhib;

  if (!(r6502_ps & DFLAG))
  {
    nval = r6502_a+n;
    if (r6502_ps & CFLAG)
      nval++;
    if (nval >= 0x100)
      SETFLAG(CFLAG)
    else
      CLEARFLAG(CFLAG)
    if (!((r6502_a ^ n) & 0x80) AND ((r6502_a ^ nval) & 0x80))
      SETFLAG(VFLAG)
    else
      CLEARFLAG(VFLAG)
    nval &= 0xFF;
    r6502_a = nval;
    SETNFLAG(r6502_a)
    SETZFLAG(r6502_a)
  }
  else
  {
    nval = r6502_a+n;
    if (r6502_ps & CFLAG)
      nval++;
    SETZFLAG(nval)
    nlob = (r6502_a & 0x0F)+(n & 0x0F);
    if (r6502_ps & CFLAG)
      nlob++;
    if (nlob > 9)
      nlob += 6;
    nhib = (r6502_a >> 4)+(n >> 4);
    if (nlob > 0x0F)
      nhib++;
    nval = (nhib << 4) + (nlob & 0x0F);
    SETNFLAG(nval)
    if ((((nhib << 4) ^ r6502_a) & 0x80) AND !((r6502_a ^ n) & 0x80))
      SETFLAG(VFLAG)
    else
      CLEARFLAG(VFLAG)
    if (nhib > 9)
      nhib +=6;
    if (nhib > 0x0F)
      SETFLAG(CFLAG)
    else
      CLEARFLAG(CFLAG)
    r6502_a = (nhib << 4) + (nlob & 0x0F);
  }
}

void r6502jsr(int r6502_pc) /*,int address)*/
{
  r6502_pc--;
  STACK_PUSH((r6502_pc & 0xFF00)>>8);
  STACK_PUSH(r6502_pc & 0x00FF);
  /*r6502_pc = n;*/
  /*goto address;*/
  /*setjmp(jmpbuffer);*/
}

/*void r6502rts(void)
{
  int r6502_pc;
  STACK_POP(nlo);
  STACK_POP(nhi);
  r6502_pc = (nhi<<8)+nlo;
  r6502_pc++;*/
 /* longjump(jmpbuffer,value);*/
/*}*/

void r6502sbc(int n)
{
  int nval;
  int nlob, nhib;
  if (!(r6502_ps & DFLAG))
  {
    nval = r6502_a-n;
    if (!(r6502_ps & CFLAG))
      nval--;
    if (nval >= 0)
      SETFLAG(CFLAG)
    else
      CLEARFLAG(CFLAG)
    if (((r6502_a ^ nval) & 0x80) AND ((r6502_a ^ n) & 0x80))
      SETFLAG(VFLAG)
    else
      CLEARFLAG(VFLAG)
    nval &= 0xFF;
    SETNFLAG(nval)
    SETZFLAG(nval)
    r6502_a = nval;
  }
  else
  {
    nval = r6502_a-n;
    if (!(r6502_ps & CFLAG))
      nval--;
    nlob = (r6502_a & 0x0F)-(n & 0x0F);
    if (!(r6502_ps & CFLAG))
      nlob--;
    nhib = (r6502_a >> 4)-(n >> 4);
    if (nlob & 0x10)
    {
      nlob -= 6;
      nlob &= 0x0F;
      nhib--;
    }
    if (nhib & 0x10)
      nhib -= 6;
    if (nval >= 0)
      SETFLAG(CFLAG)
    else
      CLEARFLAG(CFLAG)
    if (((r6502_a ^ nval) & 0x80) AND ((r6502_a ^ n) & 0x80))
      SETFLAG(VFLAG)
    else
      CLEARFLAG(VFLAG)
    nval &= 0xFF;
    SETNFLAG(nval)
    SETZFLAG(nval)
    r6502_a = (nhib << 4) + (nlob & 0x0F);
  }
}

/*char mode2readlow(int address)
{*/
  /*screen address calulation routine by Michael Foot <mjfoot@paradise.net.nz>*/
  /*this is slow*/
  /*int nx,ny;
  char pixel1,pixel2;
  char *cscreen;

  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;
  nx = (address & 0xFFF8);
  nx = ((nx % 0x280) >> 2);

  ny = ((address / 0x280) << 3);
  ny += (address & 7);*/

  /*ny * 160*/
  /*address = (loc_video_addr + (ny << 7) + (ny << 5) + nx);
  cscreen = (char *)address;
  pixel1 = (cscreen[0] & 0x0F);
  pixel2 = (cscreen[1] & 0x0F);*/

  /*&08 &04 &02 &01*/
  /*pixel1 = ((pixel1 & 0x08)<<4) | ((pixel1 & 0x04)<<3) | ((pixel1 & 0x02)<<2)
| ((pixel1 & 0x01)<<1);*/

  /*&08 &04 &02 &01*/
  /*pixel2 = ((pixel2 & 0x08)<<3) | ((pixel2 & 0x04)<<2) | ((pixel2 & 0x02)<<1)
| (pixel2 & 0x01);

  return (pixel1 | pixel2);
}*/

char mode2read16(int address)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  char *cscreen;
  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 80, divide by 16 first, since 5*16=80*/
  ny = (address >> 4);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*60) = offset - y*64 - y*16*/
  nx = address - (ny << 3) - (ny << 1);

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 160*/
  address = (loc_video_addr + (ny << 7) + (ny << 5) + (nx<<1));
  cscreen = (char *)address;
  pixel1 = (cscreen[0] & 0x0F);
  pixel2 = (cscreen[1] & 0x0F);

  /*&08 &04 &02 &01*/
  pixel1 = ((pixel1 & 0x08)<<4) | ((pixel1 & 0x04)<<3) | ((pixel1 & 0x02)<<2) |
((pixel1 & 0x01)<<1);

  /*&08 &04 &02 &01*/
  pixel2 = ((pixel2 & 0x08)<<3) | ((pixel2 & 0x04)<<2) | ((pixel2 & 0x02)<<1) |
(pixel2 & 0x01);

  return (pixel1 | pixel2);
}

char mode5read16(int address)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  char *cscreen;
  address -= 0x5800;
  if (address >= 0x2800)
    address &= 0x27FF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 40, divide by 8 first, since 5*8=40*/
  ny = (address >> 3);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*40) = offset - y*32 - y*/
  nx = address - (ny << 2) - ny;

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 160*/
  address = (loc_video_addr + (ny << 7) + (ny << 5) + (nx << 2));
  cscreen = (char *)address;

  pixel1 = (cscreen[0] & 0x0F);
  pixel2 = (cscreen[1] & 0x0F);

  /*&08 &04 &02 &01*/
  pixel1 = ((pixel1 & 0x08)<<4) | ((pixel1 & 0x04)<<3) | ((pixel1 & 0x02)<<2) |
((pixel1 & 0x01)<<1);

  /*&08 &04 &02 &01*/
  pixel2 = ((pixel2 & 0x08)<<3) | ((pixel2 & 0x04)<<2) | ((pixel2 & 0x02)<<1) |
(pixel2 & 0x01);

  return (pixel1 | pixel2);
}

char mode2read256(int address)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  char *cscreen;
  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 80, divide by 16 first, since 5*16=80*/
  ny = (address >> 4);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*60) = offset - y*64 - y*16*/
  nx = address - (ny << 3) - (ny << 1);

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 640 + nx * 8*/
//  address = (loc_video_addr + (((ny << 7) + (ny << 5) + (nx<<1))<<1));
  address = (loc_video_addr + ((ny << 9) + (ny << 7)) + (nx<<3));
  cscreen = (char *)address;
  pixel1 = (cscreen[0] & 0x0F);
  pixel2 = (cscreen[4] & 0x0F);

  /*&08 &04 &02 &01*/
  pixel1 = ((pixel1 & 0x08)<<4) | ((pixel1 & 0x04)<<3) | ((pixel1 & 0x02)<<2) | ((pixel1 & 0x01)<<1);

  /*&08 &04 &02 &01*/
  pixel2 = ((pixel2 & 0x08)<<3) | ((pixel2 & 0x04)<<2) | ((pixel2 & 0x02)<<1) | (pixel2 & 0x01);

  return (pixel1 | pixel2);
}

char mode5read256(int address)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2,pixel3,pixel4;
  char *cscreen;
  address -= 0x5800;
  if (address >= 0x2800)
    address &= 0x27FF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 40, divide by 8 first, since 5*8=40*/
  ny = (address >> 3);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*40) = offset - y*32 - y*/
  nx = address - (ny << 2) - ny;

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 160*/
/*  address = (loc_video_addr + (ny << 7) + (ny << 5) + (nx << 2)); */
  address = (loc_video_addr + ((ny << 9) + (ny << 7)) + (nx<<4));
  cscreen = (char *)address;

  pixel1 = (cscreen[0] & 0x03);
  pixel2 = (cscreen[4] & 0x03);
  pixel3 = (cscreen[8] & 0x03);
  pixel4 = (cscreen[12] & 0x03);

  pixel1 = ((pixel1 & 0x02)<<6) | ((pixel1 & 0x01)<<3);
  pixel2 = ((pixel2 & 0x02)<<5) | ((pixel2 & 0x01)<<2);
  pixel3 = ((pixel3 & 0x02)<<4) | ((pixel3 & 0x01)<<1);
  pixel4 = ((pixel4 & 0x02)<<3) | ((pixel4 & 0x01)<<0);

  return (pixel1 | pixel2 | pixel3 | pixel4);
}



char mode2read256dh(int address)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  char *cscreen;
  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 80, divide by 16 first, since 5*16=80*/
  ny = (address >> 4);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*60) = offset - y*64 - y*16*/
  nx = address - (ny << 3) - (ny << 1);

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 640 + nx * 8*/
//  address = (loc_video_addr + (((ny << 7) + (ny << 5) + (nx<<1))<<1));
  address = (loc_video_addr + (((ny << 9) + (ny << 7))<<1) + (nx<<3));
  cscreen = (char *)address;
  pixel1 = (cscreen[0] & 0x0F);
  pixel2 = (cscreen[4] & 0x0F);

  /*&08 &04 &02 &01*/
  pixel1 = ((pixel1 & 0x08)<<4) | ((pixel1 & 0x04)<<3) | ((pixel1 & 0x02)<<2) | ((pixel1 & 0x01)<<1);

  /*&08 &04 &02 &01*/
  pixel2 = ((pixel2 & 0x08)<<3) | ((pixel2 & 0x04)<<2) | ((pixel2 & 0x02)<<1) | (pixel2 & 0x01);

  return (pixel1 | pixel2);
}

char mode5read256dh(int address)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2,pixel3,pixel4;
  char *cscreen;
  address -= 0x5800;
  if (address >= 0x2800)
    address &= 0x27FF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 40, divide by 8 first, since 5*8=40*/
  ny = (address >> 3);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*40) = offset - y*32 - y*/
  nx = address - (ny << 2) - ny;

  /*add back low 3 bits*/
  ny += nyo;

  address = (loc_video_addr + (((ny << 9) + (ny << 7))<<1) + (nx<<4));
  cscreen = (char *)address;

  pixel1 = (cscreen[0] & 0x03);
  pixel2 = (cscreen[4] & 0x03);
  pixel3 = (cscreen[8] & 0x03);
  pixel4 = (cscreen[12] & 0x03);

  pixel1 = ((pixel1 & 0x02)<<6) | ((pixel1 & 0x01)<<3);
  pixel2 = ((pixel2 & 0x02)<<5) | ((pixel2 & 0x01)<<2);
  pixel3 = ((pixel3 & 0x02)<<4) | ((pixel3 & 0x01)<<1);
  pixel4 = ((pixel4 & 0x02)<<3) | ((pixel4 & 0x01)<<0);

  return (pixel1 | pixel2 | pixel3 | pixel4);
}

char mode7read(int address)
{
	return memory[address];
}

char r6502read(int address)
{
  char result;

  if (address | 0x10000)
    address &= 0xFFFF;
  switch (address & 0xF000)
  {
    case 0x0000:
    case 0x1000:
    case 0x2000:
      /*RAM*/
      result = memory[address];
      break;
    case 0x3000:
    case 0x4000:
    case 0x5000:
    case 0x6000:
    case 0x7000:
      /*RAM*/
      if (address >= bbc_video_addr)
      {
         result = moderead(address);
      }
      else
        result = memory[address];
      break;
    case 0x8000:
    case 0x9000:
    case 0xA000:
    case 0xB000:
      /*ROM*/
      result = memory[address];
      break;
    case 0xC000:
    case 0xD000:
    case 0xE000:
      /*ROM*/
      result = memory[address];
      break;
    case 0xF000:
      result = memory[address];
      break;
    default:
      result = 0;
      break;
  }
  return (result);
}

/*void mode2writelow(int address, char value)
{*/
  /*screen address calulation routine by Michael Foot <mjfoot@paradise.net.nz>*/
  /*this is slow*/
  /*int nx,ny;
  char pixel1,pixel2;
  char *cscreen;
  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;
  nx = (address & 0xFFF8);
  nx = ((nx % 0x280) >> 2);

  ny = ((address / 0x280) << 3);
  ny += (address & 7);*/

  /*&08 &04 &02 &01*/
  /*pixel1 = ((value & 0x80)>>4) | ((value & 0x20)>>3) | ((value & 0x08)>>2) |
((value & 0x02)>>1);*/

  /*&08 &04 &02 &01*/
  /*pixel2 = ((value & 0x40)>>3) | ((value & 0x10)>>2) | ((value & 0x04)>>1) |
(value & 0x01);*/

  /*ny * 160*/
  /*address = (loc_video_addr + (ny << 7) + (ny << 5) + nx);
  cscreen = (char *)address;
  cscreen[0] = ((pixel1 << 4) | pixel1);
  cscreen[1] = ((pixel2 << 4) | pixel2);*/
/*}*/

void mode2write16(int address, char value)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  char *cscreen;

  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 80, divide by 16 first, since 5*16=80*/
  ny = (address >> 4);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*60) = offset - y*64 - y*16*/
  nx = address - (ny << 3) - (ny << 1);

  /*add back low 3 bits*/
  ny += nyo;

  /*&08 &04 &02 &01*/
  pixel1 = ((value & 0x80)>>4) | ((value & 0x20)>>3) | ((value & 0x08)>>2) |
((value & 0x02)>>1);

  /*&08 &04 &02 &01*/
  pixel2 = ((value & 0x40)>>3) | ((value & 0x10)>>2) | ((value & 0x04)>>1) |
(value & 0x01);

  /*ny * 160*/
  address = (loc_video_addr + (ny << 7) + (ny << 5) + (nx<<1));
  cscreen = (char *)address;
  /*pixel1 = videoula_palette[pixel1];*/
  cscreen[0] = ((pixel1 << 4) | pixel1);
  /*pixel2 = videoula_palette[pixel2];*/
  cscreen[1] = ((pixel2 << 4) | pixel2);
}

void mode5write16(int address, char value)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2,pixel3,pixel4;
  char *cscreen;

  address -= 0x5800;
  if (address >= 0x2800)
    address &= 0x27FF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 40, divide by 8 first, since 5*8=40*/
  ny = (address >> 3);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*40) = offset - y*32 - y*/
  nx = address - (ny << 2) - ny;

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 80*/
  address = (loc_video_addr + (ny << 6) + (ny << 4) + (nx << 1));
  cscreen = (char *)address;

  /*&02 &01*/
  pixel1 = ((value & 0x80)>>6) | ((value & 0x08)>>3);
  /*&08 &04*/
  pixel2 = ((value & 0x40)>>5) | ((value & 0x04)>>2);
  /*&20 &10*/
  pixel3 = ((value & 0x20)>>4) | ((value & 0x02)>>1);
  /*&80 &40*/
  pixel4 = ((value & 0x10)>>3) | (value & 0x01);

  cscreen[0] = (pixel2 << 6) | (pixel2 << 4) | (pixel1 << 2) | pixel1;
  cscreen[1] = (pixel4 << 6) | (pixel4 << 4) | (pixel3 << 2) | pixel3;
}

void mode2write256(int address, char value)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  int *cscreen;
  /*printf("A=&%X V=&%X\n",address,value);*/
  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 80, divide by 16 first, since 5*16=80*/
  ny = (address >> 4);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*60) = offset - y*64 - y*16*/
  nx = address - (ny << 3) - (ny << 1);

  /*add back low 3 bits*/
  ny += nyo;

  /*&08 &04 &02 &01*/
  pixel1 = ((value & 0x80)>>4) | ((value & 0x20)>>3) | ((value & 0x08)>>2) | ((value & 0x02)>>1);

  /*&08 &04 &02 &01*/
  pixel2 = ((value & 0x40)>>3) | ((value & 0x10)>>2) | ((value & 0x04)>>1) | (value & 0x01);

  /*ny * 640 + nx * 8 */
  // address = (loc_video_addr + (((ny << 7) + (ny << 5) + (nx<<1))<<1));
  address = (loc_video_addr + ((ny << 9) + (ny << 7)) + (nx<<3));
  /*printf("X=&%X Y=&%X ADDR=&%X\n",nx,ny,address);*/
  cscreen = (int *)address;
  cscreen[0] =  (pixel1) | (pixel1 << 8) | (pixel1 << 16) | (pixel1 << 24);
  cscreen[1] =  (pixel2) | (pixel2 << 8) | (pixel2 << 16) | (pixel2 << 24);
}

void mode5write256(int address, char value)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2,pixel3,pixel4;
  int *cscreen;

  address -= 0x5800;
  if (address >= 0x2800)
    address &= 0x27FF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 40, divide by 8 first, since 5*8=40*/
  ny = (address >> 3);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*40) = offset - y*32 - y*/
  nx = address - (ny << 2) - ny;

  /*add back low 3 bits*/
  ny += nyo;

  /*ny * 80*/
  address = (loc_video_addr + ((ny << 9) + (ny << 7)) + (nx<<4));
  cscreen = (int *)address;

  /*&02 &01*/
  pixel1 = ((value & 0x80)>>6) | ((value & 0x08)>>3);
  /*&08 &04*/
  pixel2 = ((value & 0x40)>>5) | ((value & 0x04)>>2);
  /*&20 &10*/
  pixel3 = ((value & 0x20)>>4) | ((value & 0x02)>>1);
  /*&80 &40*/
  pixel4 = ((value & 0x10)>>3) | (value & 0x01);

  cscreen[0] =  (pixel1) | (pixel1 << 8) | (pixel1 << 16) | (pixel1 << 24);
  cscreen[1] =  (pixel2) | (pixel2 << 8) | (pixel2 << 16) | (pixel2 << 24);
  cscreen[2] =  (pixel3) | (pixel3 << 8) | (pixel3 << 16) | (pixel3 << 24);
  cscreen[3] =  (pixel4) | (pixel4 << 8) | (pixel4 << 16) | (pixel4 << 24);
}

void mode2write256dh(int address, char value)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2;
  int *cscreen;
  /*printf("A=&%X V=&%X\n",address,value);*/
  address -= 0x3000;
  if (address >= 0x5000)
    address &= 0x4FFF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 80, divide by 16 first, since 5*16=80*/
  ny = (address >> 4);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*60) = offset - y*64 - y*16*/
  nx = address - (ny << 3) - (ny << 1);

  /*add back low 3 bits*/
  ny += nyo;

  /*&08 &04 &02 &01*/
  pixel1 = ((value & 0x80)>>4) | ((value & 0x20)>>3) | ((value & 0x08)>>2) | ((value & 0x02)>>1);

  /*&08 &04 &02 &01*/
  pixel2 = ((value & 0x40)>>3) | ((value & 0x10)>>2) | ((value & 0x04)>>1) | (value & 0x01);

  /*ny * 640 + nx * 8 */
  // address = (loc_video_addr + (((ny << 7) + (ny << 5) + (nx<<1))<<1));
  address = (loc_video_addr + (((ny << 9) + (ny << 7))<<1) + (nx<<3));
  /*printf("X=&%X Y=&%X ADDR=&%X\n",nx,ny,address);*/
  cscreen = (int *)address;
//  *cscreen =  (pixel1) | (pixel1 << 8) | (pixel2 << 16) | (pixel2 << 24);
  cscreen[0] =  (pixel1) | (pixel1 << 8) | (pixel1 << 16) | (pixel1 << 24);
  cscreen[1] =  (pixel2) | (pixel2 << 8) | (pixel2 << 16) | (pixel2 << 24);
  cscreen[160] = (pixel1) | (pixel1 << 8) | (pixel1 << 16) | (pixel1 << 24);
  cscreen[161] = (pixel2) | (pixel2 << 8) | (pixel2 << 16) | (pixel2 << 24);
}

void mode5write256dh(int address, char value)
{
  /*screen address calulation routine by Thomas Harte <t.harte@excite.com>*/
  /*this is fast*/
  int nx,ny,nyo;
  char pixel1,pixel2,pixel3,pixel4;
  int *cscreen;

  address -= 0x5800;
  if (address >= 0x2800)
    address &= 0x27FF;

  nyo = (address & 7);

  /*take away bottom 3 bits*/
  address >>= 3;

  /*in order to divide by 40, divide by 8 first, since 5*8=40*/
  ny = (address >> 3);

  /*now divide by 5 using a numeric method based on the observation that
    x/5 = x/4 - x/10, and hence x/10 = x/8 - x/20, etc.
    a few fractional bits are used to maintain some accuracy - either 3
    or 5 depending on the low bit, since this produces the right result*/
  if (ny & 1)
  {
    ny = + (ny << 1) - (ny >> 1)
       + (ny >> 3) - (ny >> 5)
       + (ny >> 7);
    ny &= ~7;
  }
  else
  {
    ny = + (ny << 3) - (ny << 1)
       + (ny >> 1) - (ny >> 3)
       + (ny >> 5) - (ny >> 7);
    ny = (ny >> 2) & ~7;
  }

  /*get x just with address - (y*40) = offset - y*32 - y*/
  nx = address - (ny << 2) - ny;

  /*add back low 3 bits*/
  ny += nyo;

  address = (loc_video_addr + (((ny << 9) + (ny << 7))<<1) + (nx<<4));
  cscreen = (int *)address;

  /*&02 &01*/
  pixel1 = ((value & 0x80)>>6) | ((value & 0x08)>>3);
  /*&08 &04*/
  pixel2 = ((value & 0x40)>>5) | ((value & 0x04)>>2);
  /*&20 &10*/
  pixel3 = ((value & 0x20)>>4) | ((value & 0x02)>>1);
  /*&80 &40*/
  pixel4 = ((value & 0x10)>>3) | (value & 0x01);

  cscreen[0] =  (pixel1) | (pixel1 << 8) | (pixel1 << 16) | (pixel1 << 24);
  cscreen[1] =  (pixel2) | (pixel2 << 8) | (pixel2 << 16) | (pixel2 << 24);
  cscreen[2] =  (pixel3) | (pixel3 << 8) | (pixel3 << 16) | (pixel3 << 24);
  cscreen[3] =  (pixel4) | (pixel4 << 8) | (pixel4 << 16) | (pixel4 << 24);
  cscreen[160] =  (pixel1) | (pixel1 << 8) | (pixel1 << 16) | (pixel1 << 24);
  cscreen[161] =  (pixel2) | (pixel2 << 8) | (pixel2 << 16) | (pixel2 << 24);
  cscreen[162] =  (pixel3) | (pixel3 << 8) | (pixel3 << 16) | (pixel3 << 24);
  cscreen[163] =  (pixel4) | (pixel4 << 8) | (pixel4 << 16) | (pixel4 << 24);
}

void mode7write(int address, char value)
{
  char nx,ny;
  address -= 0x7C00;
  if (address >= 0x3E8)
    address -= 0x3E8;
  ny = (address / 40);
  nx = (address % 40);
  bbcvdu(31);
  bbcvdu(nx);
  bbcvdu(ny);
  bbcvdu(value | 0x80);
}

void videoulawrite(int address, char value)
{
  char n1,n2;
  if (address & 0x01)
  {
    /*palette*/
    n1 = (value >> 4); /*logical colour*/
    n2 = ((value & 0x0F) ^ 7); /*physical colour*/
    videoula_palettevalue = value;
    switch (bbc_video_mode)
    {
      case 0x00:
      case 0x03:
      case 0x04:
      case 0x06:
        /*1bpp*/
        videoula_palette0[n1] = videoula_physical0[n2];
        videoula_palette1[n1] = videoula_physical1[n2];
        n2 = video_colourlookup1[n1];
        if (videoula_flashcolour == 0)
          videoula_palette[n2] = videoula_palette0[n1];
        else
          videoula_palette[n2] = videoula_palette1[n1];
        break;
      case 0x01:
      case 0x05:
        /*2bpp*/
        videoula_palette0[n1] = videoula_physical0[n2];
        videoula_palette1[n1] = videoula_physical1[n2];
        n2 = video_colourlookup2[n1];
        if (videoula_flashcolour == 0)
          videoula_palette[n2] = videoula_palette0[n1];
        else
          videoula_palette[n2] = videoula_palette1[n1];
        break;
      default:
        videoula_palette0[n1] = videoula_physical0[n2];
        videoula_palette1[n1] = videoula_physical1[n2];
        if (videoula_flashcolour == 0)
          videoula_palette[n1] = videoula_palette0[n1];
        else
          videoula_palette[n1] = videoula_palette1[n1];
        break;
    }
  }
  else
    videoula_flashcolour = (value & 0x01);
}

void sheilawrite(int address, char value)
{
  switch (address & 0x00F4)
  {
    case 0x20:
    case 0x24:
    case 0x28:
    case 0x2C:
      /*&FE20 - &FE2F (VIDEOULA)*/
      videoulawrite(address, value);
      break;
  }
}

void r6502write(int address, char value)
{
  if (address | 0x10000)
    address &= 0xFFFF;
  switch (address & 0xF000)
  {
    case 0x0000:
    case 0x1000:
    case 0x2000:
      /*RAM*/
      memory[address] = value;
      break;
    case 0x3000:
    case 0x4000:
    case 0x5000:
    case 0x6000:
    case 0x7000:
      /*RAM*/
      memory[address] = value;
      /*check screen write here!*/
      if (address >= bbc_video_addr)
      {
         modewrite(address,value);
      }
      break;
    case 0x8000:
    case 0x9000:
    case 0xA000:
    case 0xB000:
      /*ROM*/
      break;
    case 0xC000:
    case 0xD000:
    case 0xE000:
      /*ROM*/
      break;
    case 0xF000:
      switch (address & 0x0F00)
      {
        case 0x0E00:
          sheilawrite(address, value);
          break;
      }
      break;
  }
}


void getscreenaddress(void)
{
  setword(buffer1,148);
  setword(buffer1+4,-1);
  regs.r[0] = (int)buffer1;
  regs.r[1] = (int)buffer2;
  _kernel_swi(OS_ReadVduVariables,&regs,&regs);
  loc_video_addr = getword(buffer2);
}

void setscreenmode(int mode)
{
  int smb[16]; /* Screen memory block */
  int x_eig;
  int char_scaling;

  if (mode == 7)
  {
	  /* Mode 7 is handled by the OS */
      if (outline_font && font_handle)
      {
	     _swix(Font_LoseFont, _IN(0), font_handle);
		 font_handle = 0;
	  }
	  moderead = mode7read;
	  modewrite = mode7write;
      vdu_text = bbcvdu;

	  bbcvdu(22);
	  bbcvdu(mode);
	  return;
  }

  vdu_text = bbcvdu;

  /* Common fields */
  smb[0] = 1;
  smb[1] = 640; /* x res */
  smb[2] = 256; /* y res */
  smb[4] = -1; /* max refresh rate */

  if (double_height) smb[2] = 512;

  switch(mode)
  {
  case 2: // Mode 2
  case 5: // Mode 5
	  x_eig =  3;
	  char_scaling = 5; /* Get 20 chars per row */
	  break;

  default:
	  x_eig = 1;
	  char_scaling = 1;
	  break;
  }

  if (screen_256colour)
  {
	  smb[3] = 3; /* 8 bpp */
	  /* Note: Need to set ModeFlags to 128 and NColour variables to 255 get full 8 bit palette */
	  smb[5] = 0; smb[6] = 128; /* Mode flags */
	  smb[7] = 3; smb[8] = 255; /* NColour (number of colours -1) */

	  smb[9] = 4;   smb[10] = x_eig; /* X eig */
	  smb[11] = 5;  smb[12] = (double_height) ? 1 : 2; /* Y eig */
	  smb[13] = 10; smb[14] = char_scaling;

	  smb[15] = -1; /* End of list */

	  /* Set up read/write routines */
	  if (double_height)
	  {
		switch(mode)
		{
		case 2:
			moderead = mode2read256dh;
			modewrite = mode2write256dh;
			break;
		case 5:
			moderead = mode5read256dh;
			modewrite = mode5write256dh;
			break;
		}
	  } else
	  {
		switch(mode)
		{
		case 2:
			moderead = mode2read256;
			modewrite = mode2write256;
			break;
		case 5:
			moderead = mode5read256;
			modewrite = mode5write256;
			break;
		}
	  }
  } else
  {
	  smb[3] = 2; /* 4 bpp */
	  smb[5] = 4;  smb[6] = x_eig; /* X eig */
	  smb[7] = 5;  smb[8] = 1; /* Y eig */
	  smb[9] = 10; smb[10] = char_scaling;

	  smb[11] = -1; /* End of list */

	  switch(mode)
	  {
	 	case 2:
			moderead = mode2read16;
			modewrite = mode2write16;
			break;
	 	case 5:
			moderead = mode5read16;
			modewrite = mode5write16;
			break;
	  }
  }

  _swi(OS_ScreenMode, _INR(0,1), 0, smb);

  if (screen_256colour)
  {
  	  char osword12[5]; /* palette setting block */
	  int pal;

	  /* Set to default palette */
	  osword12[2] = osword12[3] = osword12[4] = 0;

	  if (mode == 5)
	  {
		for (pal = 0; pal < 4; pal++)
		{
			osword12[0] = pal;
			switch(pal)
			{
			case 2: osword12[1] = 3; break;
			case 3: osword12[1] = 7; break;
			default:
				osword12[1] = pal;
				break;
			}
			_swix(OS_Word, _INR(0,1), 12, osword12);
		}
	  } else
	  {
		for (pal = 0; pal < 16; pal++)
		{
			osword12[0] = pal;
			osword12[1] = pal;
			_swix(OS_Word, _INR(0,1), 12, osword12);
		}
	  }
  }

  if (double_height)
  {
	  /* Set VDU5 char size to double height */
	  bbcvdu(23);bbcvdu(17);bbcvdu(7);
	  bbcvdu(2); /* Change character size flag */
	  bbcvdu(8); bbcvdu(0);  /* x size 8 */
	  bbcvdu(16); bbcvdu(0); /* y size 16 */
	  bbcvdu(0); bbcvdu(0);  /* Padding */
  }

  graphics_foreground = 7;
  graphics_background = 0;
  text_foreground = 7;
  text_background = 0;

  if (outline_font)
  {
     if (font_handle) _swix(Font_LoseFont, _IN(0), font_handle);
	 /* Wide characters used for mode 2 messes with font width required */
     if (_swix(Font_FindFont, _INR(1,5) |_OUT(0), 
               "Corpus.Bold", (580<<2), 338, 0, 0,
               &font_handle) != NULL)
     {
        font_handle = 0;
        vdu_text = bbcvdu;
     } else
     {
		 int i;
        vdu_text = font_text;
        _swix(Font_ReadInfo, _IN(0)|_OUT(4), font_handle, &base_line);
		if (base_line > 0) base_line-=2 + (double_height<<1);
		last_font_foreground = -1;
		last_font_background = -1;
		vdu_intercept[19].execute = vdu19font;
		for (i = 0; i < 16; i++)
			font_palette[i] = mode_palette[i];
     }
  }

  WAIT_FOR_VERTICAL_SYNC

  bbc_video_mode = mode;
  bbc_video_addr = video_base_addr[mode];

  getscreenaddress();

}

/**
 * Intercept screen mode changes
 */
void vdu22(void)
{
	setscreenmode(vdu_buffer[1]);
}

/**
 * Simple pass through intercept, used so
 * that only text characters are passed to
 * vdu_text
 */
void vdupass(void)
{
	int i;
	for (i = 0; i < vdu_count;i++)
		bbcvdu(vdu_buffer[i]);
}

/**
 * Initialise game
 *
 * Returns: 1 if successful otherwise 0.
 */
int initialise(void)
{
  int i,address;
  char buffer[9]; /*pixel map for character*/

    /*vdu character font lookup table*/
  address = 0xC000;
  for (i = 32; i < 128; i++)
  {
    buffer[0] = i;
    regs.r[0] = 10;
    regs.r[1] = (int)buffer;
    _kernel_swi(OS_Word,&regs,&regs);
    /*buffer now contains {char,int[0...7]}*/
    /*     0,  1, 2, 3, 4, 5, 6, 7,8*/
    /*i.e. T,126,24,24,24,24,24,24,0*/
    memory[address+0x00] = buffer[1];
    memory[address+0x01] = buffer[2];
    memory[address+0x02] = buffer[3];
    memory[address+0x03] = buffer[4];
    memory[address+0x04] = buffer[5];
    memory[address+0x05] = buffer[6];
    memory[address+0x06] = buffer[7];
    memory[address+0x07] = buffer[8];
    address += 0x08;
  }

  /*set up keyboard translation table*/
  memory[0xF02B] = 0x03;
  memory[0xF02C] = 0x8C;
  memory[0xF02D] = 0x40;
  memory[0xF02E] = 0xFE;
  memory[0xF02F] = 0xA0;
  memory[0xF030] = 0x7F;
  memory[0xF031] = 0x8C;
  memory[0xF032] = 0x43;
  memory[0xF033] = 0xFE;
  memory[0xF034] = 0x8E;
  memory[0xF035] = 0x4F;
  memory[0xF036] = 0xFE;
  memory[0xF037] = 0xAE;
  memory[0xF038] = 0x4F;
  memory[0xF039] = 0xFE;
  memory[0xF03A] = 0x60;
  memory[0xF03B] = 0x71;
  memory[0xF03C] = 0x33;
  memory[0xF03D] = 0x34;
  memory[0xF03E] = 0x35;
  memory[0xF03F] = 0x84;
  memory[0xF040] = 0x38;
  memory[0xF041] = 0x87;
  memory[0xF042] = 0x2D;
  memory[0xF043] = 0x5E;
  memory[0xF044] = 0x8C;
  memory[0xF045] = 0x84;
  memory[0xF046] = 0xEC;
  memory[0xF047] = 0x86;
  memory[0xF048] = 0xED;
  memory[0xF049] = 0x60;
  memory[0xF04A] = 0x00;
  memory[0xF04B] = 0x80;
  memory[0xF04C] = 0x77;
  memory[0xF04D] = 0x65;
  memory[0xF04E] = 0x74;
  memory[0xF04F] = 0x37;
  memory[0xF050] = 0x69;
  memory[0xF051] = 0x39;
  memory[0xF052] = 0x30;
  memory[0xF053] = 0x5F;
  memory[0xF054] = 0x8E;
  memory[0xF055] = 0x6C;
  memory[0xF056] = 0xFE;
  memory[0xF057] = 0xFD;
  memory[0xF058] = 0x6C;
  memory[0xF059] = 0xFA;
  memory[0xF05A] = 0x00;
  memory[0xF05B] = 0x31;
  memory[0xF05C] = 0x32;
  memory[0xF05D] = 0x64;
  memory[0xF05E] = 0x72;
  memory[0xF05F] = 0x36;
  memory[0xF060] = 0x75;
  memory[0xF061] = 0x6F;
  memory[0xF062] = 0x70;
  memory[0xF063] = 0x5B;
  memory[0xF064] = 0x8F;
  memory[0xF065] = 0x2C;
  memory[0xF066] = 0xB7;
  memory[0xF067] = 0xD9;
  memory[0xF068] = 0x6C;
  memory[0xF069] = 0x28;
  memory[0xF06A] = 0x02;
  memory[0xF06B] = 0x01;
  memory[0xF06C] = 0x61;
  memory[0xF06D] = 0x78;
  memory[0xF06E] = 0x66;
  memory[0xF06F] = 0x79;
  memory[0xF070] = 0x6A;
  memory[0xF071] = 0x6B;
  memory[0xF072] = 0x40;
  memory[0xF073] = 0x3A;
  memory[0xF074] = 0x0D;
  memory[0xF075] = 0x00;
  memory[0xF076] = 0xFF;
  memory[0xF077] = 0x01;
  memory[0xF078] = 0x02;
  memory[0xF079] = 0x09;
  memory[0xF07A] = 0x0A;
  memory[0xF07B] = 0x02;
  memory[0xF07C] = 0x73;
  memory[0xF07D] = 0x63;
  memory[0xF07E] = 0x67;
  memory[0xF07F] = 0x68;
  memory[0xF080] = 0x6E;
  memory[0xF081] = 0x6C;
  memory[0xF082] = 0x3B;
  memory[0xF083] = 0x5D;
  memory[0xF084] = 0x7F;
  memory[0xF085] = 0xAC;
  memory[0xF086] = 0x44;
  memory[0xF087] = 0x02;
  memory[0xF088] = 0xA2;
  memory[0xF089] = 0x00;
  memory[0xF08A] = 0x60;
  memory[0xF08B] = 0x00;
  memory[0xF08C] = 0x7A;
  memory[0xF08D] = 0x20;
  memory[0xF08E] = 0x76;
  memory[0xF08F] = 0x62;
  memory[0xF090] = 0x6D;
  memory[0xF091] = 0x2C;
  memory[0xF092] = 0x2E;
  memory[0xF093] = 0x2F;
  memory[0xF094] = 0x8B;
  memory[0xF095] = 0xAE;
  memory[0xF096] = 0x41;
  memory[0xF097] = 0x02;
  memory[0xF098] = 0x4C;
  memory[0xF099] = 0xAD;
  memory[0xF09A] = 0xE1;
  memory[0xF09B] = 0x1B;
  memory[0xF09C] = 0x81;
  memory[0xF09D] = 0x82;
  memory[0xF09E] = 0x83;
  memory[0xF09F] = 0x85;
  memory[0xF0A0] = 0x86;
  memory[0xF0A1] = 0x88;
  memory[0xF0A2] = 0x89;
  memory[0xF0A3] = 0x5C;
  memory[0xF0A4] = 0x8D;
  memory[0xF0A5] = 0x6C;
  memory[0xF0A6] = 0x20;
  memory[0xF0A7] = 0x02;
  memory[0xF0A8] = 0xD0;
  memory[0xF0A9] = 0xEB;
  memory[0xF0AA] = 0xA2;

  bbc_video_mode = 0x07;
  bbc_video_addr = 0x7C00;
  moderead = mode7read;
  modewrite = mode7write;

  quit = FALSE;

  /* Start with no vdu intercepts */
  for (i = 0; i < 32; i++)
  {
	  vdu_intercept[i].num_chars = 0;
  }

  /* Intercept screen mode changes */
  vdu_intercept[22].num_chars = 2;
  vdu_intercept[22].execute = vdu22;

  /* Set multi byte vdus to be passed straight through
   * so their arguments don't go to the text routine */
  vdu_intercept[1].num_chars = 2;   vdu_intercept[1].execute = vdupass;
  vdu_intercept[17].num_chars = 2;  vdu_intercept[17].execute = vdupass;
  vdu_intercept[18].num_chars = 3;  vdu_intercept[18].execute = vdupass;
  vdu_intercept[19].num_chars = 6;  vdu_intercept[19].execute = vdupass;
  vdu_intercept[23].num_chars = 10; vdu_intercept[23].execute = vdupass;
  vdu_intercept[24].num_chars = 9;  vdu_intercept[24].execute = vdupass;
  vdu_intercept[25].num_chars = 6;  vdu_intercept[25].execute = vdupass;
  vdu_intercept[28].num_chars = 5;  vdu_intercept[28].execute = vdupass;
  vdu_intercept[29].num_chars = 5;  vdu_intercept[29].execute = vdupass;
  vdu_intercept[31].num_chars = 3;  vdu_intercept[31].execute = vdupass;

  /* By default use vdu 5 text */
  vdu_text = bbcvdu;

  /* Check if we can use 640x512x256 (mode 21 equivalent) */
  if (double_height)
  {
	regs.r[0] = 21;
	if (_kernel_swi_c(OS_CheckModeValid,&regs,&regs, &i) != NULL || i)
	{
		double_height = 0;
	} else
		screen_256colour = 1; /* Double height uses 256 colour mode */
  }

  if (screen_256colour && double_height == 0)
  {
	  regs.r[0] = 15; /* Check if we can use 640x256x256 */
	  if (_kernel_swi_c(OS_CheckModeValid,&regs,&regs, &i) != NULL || i)
	  {
		  screen_256colour = 0;
	  }
  }

  if (screen_256colour == 0)
  {
	/*check to see if low colour screen modes can be used*/
	regs.r[0] = 12; /*MODE 12*/
    if (_kernel_swi_c(OS_CheckModeValid,&regs,&regs, &i) != NULL || i)
	{
		fprintf(stderr, "Can't get a suitable screen mode\n");
		return 0;
	}
  }

  if (screen_256colour)
  {
	/* Need to intercept the colour setting vdus */
	vdu_intercept[17].num_chars = 2;
	vdu_intercept[17].execute = vdu17setcolour;
	vdu_intercept[18].num_chars = 3;
	vdu_intercept[18].execute = vdu18setcolour;
	vdu_intercept[20].num_chars = 1;
	vdu_intercept[20].execute = vdu20reset;
  }

  /*disable escape*/
  regs.r[0] = 0xDC;
  regs.r[1] = 0xFF;
  regs.r[2] = 0x00;
  _kernel_swi(OS_Byte,&regs,&regs);
  escape = regs.r[1];

  _kernel_oscli("BeebSoundInitialise");

  /*_kernel_swi(0x75E40,&regs,&regs);*/

  return 1;
}

void finalise(void)
{
  if (font_handle) _swix(Font_LoseFont, _IN(0), font_handle);

  _kernel_oscli("BeebSoundCloseDown");
  /*_kernel_swi(0x75E41,&regs,&regs);*/

  /*RMKILL BEEBSOUND*/
  strcpy(memory,"BeebSound");
  regs.r[0] = 4;
  regs.r[1] = (int)memory;
  _kernel_swi(OS_Module,&regs,&regs);

  /*enable escape*/
  regs.r[0] = 0xDC;
  regs.r[1] = escape;
  regs.r[2] = 0x00;
  _kernel_swi(OS_Byte,&regs,&regs);

  /*clear screen*/
  bbcvdu(0x0C);
  bbcvdu(4); /* Unlink graphics and text cursors */

  /* Get rid of press key or mouse to continue from desktop */
  _swix(Wimp_CommandWindow, _IN(0), -1);
}
